package main

import "fmt"
import "flag"
import "demoutil"
import "os"
import "strconv"
import "bufio"

//import "math/rand"

// Distributed System
import "shardkv"

//go run demo_server_kv.go

var DoTcp = flag.Bool("tcp", false, "communicate across tcp")
var DoAuto = flag.Bool("auto", true, "load hardcoded settings")
var Set_pid = flag.Int("pid", -1, "pid of shardmaster")

var sa [][]*shardkv.ShardKV
var gids []int64

func main() {
	Init()
	err_msg := ""
	run := true
	execute := true
	cmd := demoutil.Make_cmd()
	line := ""
	in := bufio.NewReader(os.Stdin)
	var err error
	for run {
		fmt.Printf(">>>")
		// read space-seperated cmd into several arguments
		//fmt.Scanln(&line)
		line, err = in.ReadString('\n')
		if err != nil {
			panic(err)
		} else {
			execute = cmd.ParseInput(line)
			run = cmd.GetStatus()
			//line = ""
			if execute {
				err_msg = Execute(cmd.GetTodo())
				if err_msg != "" {
					fmt.Println("Error:" + err_msg)
				}
			}
		}
	}
}
func Init() {
	os.RemoveAll("/var/tmp/824-" + strconv.Itoa(os.Getpid()))
	fmt.Println("Welcome, ShardKV :) ")
	flag.Parse()
	if *DoTcp {
		fmt.Println("connect with 'tcp'")
	} else {
		fmt.Println("Default: Connect with 'unix' instead of 'tcp'")
	}

	ngroups := 3
	nreplicas := 3
	var smh []string
	var ha [][]string

	if *DoAuto {
		gids = make([]int64, ngroups)            // each group ID
		ha = make([][]string, ngroups)           // ShardKV ports, [group][replica]
		sa = make([][]*shardkv.ShardKV, ngroups) // ShardKVs
		smh = make([]string, 3)
		if *Set_pid == -1 {
			panic("need to set the pid of shardmaster: -pid=x")
		} else {
			for i := 0; i < 3; i++ {
				smh[i] = "/var/tmp/824-" + strconv.Itoa(*Set_pid) + "/px-20331-demo_sm-" + strconv.Itoa(i)
			}
		}
		for i := 0; i < ngroups; i++ {
			gids[i] = int64(i + 100)
			sa[i] = make([]*shardkv.ShardKV, nreplicas)
			ha[i] = make([]string, nreplicas)
			for j := 0; j < nreplicas; j++ {
				ha[i][j] = demoutil.Port("demo_skv", (i*nreplicas)+j, *DoTcp)
			}
			for j := 0; j < nreplicas; j++ {
				sa[i][j] = shardkv.StartServer(gids[i], smh, ha[i], j)
			}
		}

		fmt.Printf("Default: Start %v Groups of ShardKV, each with %v replicas\n", ngroups, nreplicas)

	} else {
		panic("Haven't implement interactive manual input yet")
	}

}
func Execute(cc []string) string {
	err_msg := ""
	switch cc[0] {
	case "conn":
		var err error
		opt := 0
		if len(cc) > 2 {
			err_msg = "conn: need two arguments, " + strconv.Itoa(len(cc)-1) + " provided"
		}
		if len(cc) == 2 {
			opt, err = strconv.Atoi(cc[1])
			if err != nil || (opt != 0 && opt != 1) {
				err_msg = "conn: first argument should be 0 or 1"
			}
		}
		if err_msg == "" {
			//fmt.Println(cc, "s: ", opt)
			for j := 0; j < len(sa); j++ {
				_, servers := sa[j][0].GetConn()
				switch opt {
				case 0:
					// for display
					fmt.Printf("KV Server Group %v: \n", gids[j])
					for i := 0; i < len(servers); i++ {
						fmt.Printf("Replica %v:  %v\n", i, servers[i])
					}
				case 1:
					//for sm.join
					fmt.Printf("%v ", gids[j])
					for i := 0; i < len(servers); i++ {
						fmt.Printf("%v,", servers[i])
					}
					fmt.Println()
				}
			}
		}
	default:
		err_msg = "command not found"
	}
	return err_msg
}
